/*
 * bsp_usart.c
 *
 *  Created on: 2023年6月28日
 *      Author: mcealt_DS
 */

#include "bsp_usart.h"

#include <stdio.h>
#include <stdarg.h>

#ifdef USE_UARTDRV_H
#include "sl_uartdrv_instances.h"
#endif

/*
 * 全局变量定义
 */

Buffer_t debug_TXBuff;
Buffer_t debug_RXBuff;

Buffer_t com_TXBuff;
Buffer_t com_RXBuff;

/*
 * 局部变量定义
 */


#ifdef BSP_ENABLE_USART
void DS_usartInit(void)
{

#if !defined(__CROSSWORKS_ARM) && defined(__GNUC__)
  setvbuf(stdout, NULL, _IONBF, 0);   /*Set unbuffered mode for stdout (newlib)*/
  setvbuf(stdin, NULL, _IONBF, 0);   /*Set unbuffered mode for stdin (newlib)*/
#endif

  /*
   *  开启与UART驱动相关时钟
   */
  CMU_ClockEnable(cmuClock_HFXO, true);
  CMU_ClockEnable(cmuClock_GPIO, true);
  CMU_ClockEnable(cmuClock_USART0, true);

  /*
   * usart0 define
   */

  /*
   *  UART驱动引脚配置
   */
   GPIO_PinModeSet(USART_TX_PORT,USART_TX_PIN, gpioModePushPull, 1);     \
   GPIO_PinModeSet(USART_RX_PORT,USART_RX_PIN, gpioModeInputPull, 1);        \

   USART_InitAsync_TypeDef tUsartInit = {
            .enable       = usartEnable,                                    /* 使能USART发送与接收          */
            .refFreq      = 0,                                              /* 使用当前时钟配置来配置波特率 */
            .baudrate     = USART_BAUD,                                        /* 波特率配置                   */
            .oversampling = usartOVS16,                                     /* 16x过采样率                  */
            .databits     = USART_DATABIT,                                        /* 8位数据位                    */
            .parity       = USART_PARITY,                                         /* 无校验位                     */
            .stopbits     = USART_STOPBIT,                                        /* 1位停止位                    */
            .mvdis        = false,                                          /* 使能Majority                 */
            .prsRxEnable  = false,                                          /* 禁能PRS作为RX输入            */
            .prsRxCh      = usartPrsRxCh0                                   /* 选择PRS通道                  */
        };
    USART_InitAsync(USART, &tUsartInit);
  /*
        * 使能USART0的TX和RX
        */
   GPIO->USARTROUTE[0].ROUTEEN = GPIO_USART_ROUTEEN_TXPEN | GPIO_USART_ROUTEEN_RXPEN;
   GPIO->USARTROUTE[0].TXROUTE = (USART_TX_PORT << _GPIO_USART_TXROUTE_PORT_SHIFT)
                             | (USART_TX_PIN << _GPIO_USART_TXROUTE_PIN_SHIFT);
   GPIO->USARTROUTE[0].RXROUTE = (USART_RX_PORT << _GPIO_USART_RXROUTE_PORT_SHIFT)
                              | (USART_RX_PIN << _GPIO_USART_RXROUTE_PIN_SHIFT);


   NVIC_ClearPendingIRQ(USART0_RX_IRQn);
   NVIC_EnableIRQ(USART0_RX_IRQn);
   USART_IntEnable(USART0, USART_IEN_RXDATAV);/* 使能串口接收中断          */

   NVIC_ClearPendingIRQ(USART0_TX_IRQn);
   NVIC_EnableIRQ(USART0_TX_IRQn);
   USART_IntEnable(USART0, USART_IEN_TXC);/* 使能串口发送中断          */

}

void DS_usartTxByte( uint8_t data)
{
  USART_Tx( USART0,data );
}

uint8_t DS_usartRxByte(void)
{
    return USART_Rx( USART0 );
}

static void DS_debug_RX_IRQHandler(void);
static void DS_debug_TX_IRQHandler(void);

void USART0_RX_IRQHandler(void)
{
  DS_debug_RX_IRQHandler();
}

void USART0_TX_IRQHandler(void)
{
  DS_debug_TX_IRQHandler();
}

#else
void DS_eusartInit(EUSART_TypeDef *eusart )
{
#if( (defined USE_UARTDRV_H) && DEBUG_USART_BAUD == 9600)
  sl_uartdrv_init_instances();
#else
  #if(DEBUG_USART_BAUD <= 9600)
  EUSART_UartInit_TypeDef init = EUSART_UART_INIT_DEFAULT_LF;
  #else
  EUSART_UartInit_TypeDef init = EUSART_UART_INIT_DEFAULT_HF;
  #endif
  init.baudrate = DEBUG_USART_BAUD;
  /*= {
    .enable = eusartDisable,
    .refFreq = 0,
    .baudrate = 9600,
    .oversampling = eusartOVS0,
    .databits = eusartDataBits8,
    .parity = eusartNoParity,
    .stopbits = eusartStopbits1,
    .majorityVote = eusartMajorityVoteDisable,
    .loopbackEnable = eusartLoopbackDisable,
    .advancedSettings = NULL
  };*/

  // Set advanced Settings in config init struct
  EUSART_AdvancedInit_TypeDef advanced_init = EUSART_ADVANCED_INIT_DEFAULT;
  advanced_init.dmaWakeUpOnRx = true;
  init.advancedSettings = &advanced_init;

  // Configure GPIO pins
  CMU_ClockEnable(cmuClock_GPIO, true);

  // Configure TX and RX GPIOs
  GPIO_PinModeSet(DEBUG_USART_TX_PORT, DEBUG_USART_TX_PIN, gpioModePushPull, 1);
  GPIO_PinModeSet(DEBUG_USART_RX_PORT, DEBUG_USART_RX_PIN, gpioModeInputPull, 1);

  // Configure EUSART for basic async operation
  init.enable = eusartDisable;
  CMU_ClockEnable(cmuClock_EUSART0, true);

#if ( DEBUG_USART_BAUD <= 9600 ) //USE LFXF ONLY <9600
CMU_ClockEnable(cmuClock_LFRCO, true);
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) \
    || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
    CMU_ClockEnable(cmuClock_EM23GRPACLK, true);
    CMU_CLOCK_SELECT_SET(EM23GRPACLK, LFRCO);
#if defined(EUART_PRESENT)
    CMU_CLOCK_SELECT_SET(eusart, EM23GRPACLK);
#elif defined (EUSART_PRESENT)
    CMU_CLOCK_SELECT_SET(EUSART0CLK, EM23GRPACLK);
#endif
#elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)  \
    || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4) \
    || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5) \
    || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
    CMU_CLOCK_SELECT_SET(EUSART0CLK, LFRCO);
#else
  #error "Please assign a LF clock to EUSART instance"
#endif
    EUSART_UartInitLf(eusart, &init);
#else //USE HFXO 
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) \
    || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
    CMU_ClockEnable(cmuClock_EM01GRPACLK, true);
#if defined(EUART_PRESENT)
    CMU_CLOCK_SELECT_SET(EUART0CLK, EM01GRPACLK);
#elif defined(EUSART_PRESENT)
    CMU_CLOCK_SELECT_SET(EUSART0CLK, EM01GRPACLK);
#else
#error Missing EU(S)ART peripheral
#endif
#elif (_SILICON_LABS_32B_SERIES_2_CONFIG >= 3)
    CMU_CLOCK_SELECT_SET(EM01GRPCCLK, HFRCODPLL);
    CMU_CLOCK_SELECT_SET(EUSART0CLK, EM01GRPCCLK);
#else
  #error Unsupported board configuration
#endif
    EUSART_UartInitHf(eusart, &init);
#endif

  GPIO->EUSARTROUTE[0].ROUTEEN = GPIO_EUSART_ROUTEEN_TXPEN | GPIO_EUSART_ROUTEEN_RXPEN;
  GPIO->EUSARTROUTE[0].TXROUTE =
    (DEBUG_USART_TX_PORT << _GPIO_EUSART_TXROUTE_PORT_SHIFT)
    | (DEBUG_USART_TX_PIN << _GPIO_EUSART_TXROUTE_PIN_SHIFT);
  GPIO->EUSARTROUTE[0].RXROUTE =
    (DEBUG_USART_RX_PORT << _GPIO_EUSART_RXROUTE_PORT_SHIFT)
    | (DEBUG_USART_RX_PIN << _GPIO_EUSART_RXROUTE_PIN_SHIFT);

#endif //USE_UARTDRV_H
  // Enable RX interrupts
  NVIC_ClearPendingIRQ(EUSART0_RX_IRQn);
  NVIC_EnableIRQ(EUSART0_RX_IRQn);
  EUSART_IntEnable(eusart, EUSART_IEN_RXFL);

  // Enable TX interrupts
  NVIC_ClearPendingIRQ(EUSART0_TX_IRQn);
  NVIC_EnableIRQ(EUSART0_TX_IRQn);
  EUSART_IntEnable(eusart, EUSART_IEN_TXC);

  // Finally enable EUSART
  EUSART_Enable(eusart, eusartEnable);
}
#endif

//DEBUG USART
void DS_debugInit (void)
{
#ifdef BSP_ENABLE_USART
  DS_usartInit();
#else
  DS_eusartInit(DEBUG_USART);
#endif
  bufferInit( &debug_TXBuff,512 );//初始化环形队列
  bufferInit( &debug_RXBuff,512 );//初始化环形队列
}

void DS_debugTxByte(uint8_t data)
{
#ifdef BSP_ENABLE_USART
  DS_usartTxByte( data );
#else
  EUSART_Tx(DEBUG_USART,data);
#endif
}

void DS_debugTxbuff(uint8_t *buff, uint16_t size)
{
#if(0)
  do
    {
      DS_debugTxByte(*buff++);
    }while(size--);
#else //HXF改
  for(uint16_t i = 0; i < size; i++){
      DS_debugTxByte(buff[i]);
  }
#endif
}

//阻塞式debug串口printf
void DS_debug_PRINTF_B(const char *format,...)
{
  uint8_t UartTxBuf[1024];
  uint16_t len;
    va_list args;
    va_start(args,format);
    len = vsnprintf((char*)UartTxBuf,sizeof(UartTxBuf),(char*)format,args);
    va_end(args);
    DS_debugTxbuff(UartTxBuf,len);
}

uint8_t DS_debugRxByte(void)
{
#ifdef BSP_ENABLE_USART
  return( DS_usartRxByte() );
#else
  return( EUSART_Rx(DEBUG_USART) );
 #endif
}

static void DS_debug_RX_IRQHandler(void)
{
#ifdef BSP_ENABLE_USART
  bufferAdd( &debug_RXBuff, DS_debugRxByte());
#else
  if( EUSART_IntGet( DEBUG_USART ) & EUSART_IF_RXFL )
  {
    bufferAdd( &debug_RXBuff, DS_debugRxByte());//内部会判断中断标志
    EUSART_IntClear(DEBUG_USART, EUSART_IF_RXFL);//读完数据再清标志
  }  
#endif
}

static void DS_debug_TX_IRQHandler(void)
{
#ifdef BSP_ENABLE_USART
  if( USART_IntGet( DEBUG_USART ) & USART_IF_TXC )
  {
    USART_IntClear(USART0, USART_IF_TXC);
#else
  if( EUSART_IntGet( DEBUG_USART ) & EUSART_IF_TXC )
  {
    EUSART_IntClear(EUSART0, EUSART_IF_TXC);
#endif

    if( debug_TXBuff.count !=0 )
      DS_debugTxByte( *bufferRemove(&debug_TXBuff) );
  }
}

void EUSART0_RX_IRQHandler(void)
{
  DS_debug_RX_IRQHandler();
}

void EUSART0_TX_IRQHandler(void)
{
  DS_debug_TX_IRQHandler();
}


#ifdef BSP_ENABLE_COM
//COM USART
void DS_comInit (void)
{
  CMU_ClockEnable(cmuClock_HFXO, true);
  CMU_ClockEnable(cmuClock_GPIO, true);

  if(COM_USART == EUSART1){
      CMU_ClockEnable(cmuClock_EUSART1, true);
  }

  GPIO_PinModeSet(COM_USART_TX_PORT, COM_USART_TX_PIN, gpioModePushPull, 1);
  GPIO_PinModeSet(COM_USART_RX_PORT, COM_USART_RX_PIN, gpioModeInputPull, 1);

  EUSART_UartInit_TypeDef init = COM_USART_DEFAULT_HF;
  EUSART_UartInitHf(COM_USART, &init);

  if(COM_USART == EUSART1){
      GPIO->EUSARTROUTE[1].TXROUTE = (COM_USART_TX_PORT << _GPIO_EUSART_TXROUTE_PORT_SHIFT)
          | (COM_USART_TX_PIN << _GPIO_EUSART_TXROUTE_PIN_SHIFT);
      GPIO->EUSARTROUTE[1].RXROUTE = (COM_USART_RX_PORT << _GPIO_EUSART_RXROUTE_PORT_SHIFT)
          | (COM_USART_RX_PIN << _GPIO_EUSART_RXROUTE_PIN_SHIFT);
      GPIO->EUSARTROUTE[1].ROUTEEN = GPIO_EUSART_ROUTEEN_RXPEN | GPIO_EUSART_ROUTEEN_TXPEN;

      // Enable RX interrupts
      NVIC_ClearPendingIRQ(EUSART1_RX_IRQn);
      NVIC_EnableIRQ(EUSART1_RX_IRQn);
      EUSART_IntEnable(EUSART1, EUSART_IEN_RXFL);
      // Enable TX interrupts
      NVIC_ClearPendingIRQ(EUSART1_TX_IRQn);
      NVIC_EnableIRQ(EUSART1_TX_IRQn);
      EUSART_IntEnable(EUSART1, EUSART_IEN_TXC);

      //EUSART_Enable(COM_USART, eusartEnable);
      EUSART_IntEnable(EUSART1, EUSART_IEN_RXFL);
      EUSART_IntEnable(EUSART1, EUSART_IEN_TXC);
  }

  // Finally enable EUSART
  bufferInit( &com_TXBuff,COM_USART_BUFF_SIZE );//初始化环形队列
  bufferInit( &com_RXBuff,COM_USART_BUFF_SIZE );//初始化环形队列

#if(0) //测试IO口是否正确
  GPIO_PinModeSet(COM_USART_TX_PORT, COM_USART_TX_PIN, gpioModePushPull, 0);
  GPIO_PinModeSet(COM_USART_RX_PORT, COM_USART_RX_PIN, gpioModePushPull, 0);
  GPIO_PinOutClear(COM_USART_TX_PORT, COM_USART_TX_PIN);
  GPIO_PinOutSet(COM_USART_RX_PORT, COM_USART_RX_PIN);
#endif
}

void DS_comTxByte(uint8_t data)
{
  (void) data;
}

static void DS_com_RX_IRQHandler(void)
{
  if( EUSART_IntGet( COM_USART ) & EUSART_IF_RXFL ){
    bufferAdd( &com_RXBuff, EUSART_Rx(COM_USART));
    EUSART_IntClear(COM_USART, EUSART_IF_RXFL);//读完数据再清标志
  }
}

static void DS_com_TX_IRQHandler(void)
{
  if(EUSART_IntGet(COM_USART) & EUSART_IF_TXC ){
      EUSART_IntClear(COM_USART, EUSART_IF_TXC);
  }

  if(com_TXBuff.count !=0 ){
      EUSART_Tx(COM_USART, *bufferRemove(&com_TXBuff) );
  }

}

void EUSART1_RX_IRQHandler(void)
{
  DS_com_RX_IRQHandler();
}

void EUSART1_TX_IRQHandler(void)
{
  DS_com_TX_IRQHandler();
}

void DS_com_Txbuff(const char *ptr, int len)
{
  int i = 0;
  for(i = 0; i < len; i++){
      bufferAdd(&com_TXBuff, *ptr++);   //环形队列ADD
  }
  if(COM_USART == EUSART1){
    if( (EUSART_StatusGet(COM_USART) & EUSART_IF_TXIDLE)  && (com_TXBuff.count != 0) ){  //EUSART IDLE
        EUSART_IntSet(COM_USART, EUSART_IF_TXC);
    }
  }
}
#endif

#if !defined(__CROSSWORKS_ARM) && defined(__GNUC__)
#ifdef BSP_ENABLE_USART

int _write(int file, const char *ptr, int len)
{
  int txCount;

  (void) file;
  setvbuf(stdout,NULL,_IONBF,0);
  for( txCount = 0; txCount < len; txCount++)
  {
      bufferAdd( &debug_TXBuff , *ptr++);   //环形队列ADD
  }

  //产生TX中断
  #ifdef BSP_ENABLE_USART
    if( (USART_StatusGet( DEBUG_USART ) & USART_IF_TXIDLE)  && (debug_TXBuff.count != 0))  //USART IDLE
      USART_IntSet(DEBUG_USART, USART_IF_TXC);
  #else
    if( (EUSART_StatusGet( DEBUG_USART ) & EUSART_IF_TXIDLE)  && (debug_TXBuff.count != 0) )  //EUSART IDLE
      EUSART_IntSet(DEBUG_USART, EUSART_IF_TXC);
  #endif
  //法2：DMA

  return (len);
}
#else
void EUSART0_PRINTF(const char *format,...)
{
  uint8_t UartTxBuf[1024];
  uint16_t len;
    va_list args;
    va_start(args,format);
    len = vsnprintf((char*)UartTxBuf,sizeof(UartTxBuf),(char*)format,args);
    va_end(args);
    for( int i = 0; i < len; i++)
    {
      bufferAdd( &debug_TXBuff , UartTxBuf[i]);   //环形队列ADD
    }
    if( (EUSART_StatusGet( DEBUG_USART ) & EUSART_STATUS_TXIDLE)  && (debug_TXBuff.count != 0)  )  //EUSART IDLE
             EUSART_IntSet(DEBUG_USART, EUSART_IF_TXC);
}
#endif
#endif /* !defined( __CROSSWORKS_ARM ) && defined( __GNUC__ ) */

void debug_printf_hex(uint8_t *buff, uint16_t len)
{
  for(;len>0;len--)
    {
      debug_printf("%02X",*buff++);
    }
  debug_printf( "\r\n");
}
